﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Collections;
using HostTool.Protocol;
using System.ComponentModel;

namespace HostTool.Core
{
    public class CPU : ICPU
    {


        const int mtu = 512;
        //发送应答对应协议


        static readonly UInt16[] TxCmd = new ushort[] { 
            0x0208,
            0x0303,0x0309, 0x0327, 0x0311, 0x0312, 0x0314, 
            0x0522, 0x0524,0x0103,
            0x0102, 0x0ab0,0x0ab2,0x0ab4,0x0ab6,0x0ab8,0x0aaa,
        };

        static readonly UInt16[] RxResponse = new ushort[] {
            0x0201, 
            0x0304,0x0310, 0x0328, 0x0301, 0x0382, 0x0315, 
            0x0523, 0x0501, 
            0x0104,
            0x0101, 0x0ab1,0x0ab3,0x0ab5,0x0ab7,0x0a01,0x0aab,
        };


        byte[] txBuffer = new byte[1024 * 1024];

        int MAX_WAITTIME = 5000;

        IBoard board;

        Thread threadCmd;
        Thread threadQueryChannel;

        LinkedList<RequestPackage> listRequest = new LinkedList<RequestPackage>();


        AutoResetEvent packageEvent = new AutoResetEvent(false);


        List<FirmwareType> listFirmware = new List<FirmwareType>();

       protected BindingList<CPUChannel> listChannel=new BindingList<CPUChannel>();


       ushort QueryOffset = 0;
       ushort QueryVol = 0;


       public event EventHandler ChannelDataUpdate=null;

        public CPU(IBoard board)
        {
            this.board = board;
        }
        public CPU(IBoard board,ushort queryOffset,ushort queryVol)
        {
            this.board = board;
            this.QueryOffset = queryOffset;
            this.QueryVol = queryVol;
        }

        protected void AddFirmware(FirmwareType firmware)
        {
            listFirmware.Add(firmware);
        }

        public IList<FirmwareType> FirmwareList
        {
            get
            {
                return listFirmware.AsReadOnly();
            }
        }


        public virtual RequestPackage CreateRequest(byte transaction, byte cmd,int waitTime)
        {
            if (this is CPURecord)
            {
                return CreateRequest(transaction, cmd, new byte[] { 0x01, }, 1, waitTime);
            }
            return CreateRequest(transaction, cmd, new byte[] { 0x00, }, 1, waitTime);
        }


        public virtual RequestPackage CreateRequest(byte transaction, byte cmd, byte[] data,int dataLength,int waitTime)
        {
            RequestPackage package = new RequestPackage(this.DstPort, transaction, cmd, data,dataLength, txBuffer,waitTime);

            UInt16 txCmd = (UInt16)((transaction << 8) | cmd);

            for (int i = 0; i < TxCmd.Length; i++)
            {
                if (TxCmd[i] == txCmd)
                {
                    byte fTrans =(byte)(RxResponse[i] >> 8);
                    byte fCmd = (byte)(RxResponse[i] & 0xff);
                    package.FilterTransaction = fTrans;
                    package.FilterCmd = fCmd;
                    break;
                }
            }


            return package;

        }

        /// <summary>
        /// 最大传输单元
        /// </summary>
        public virtual int MTU
        {
            get
            {
                return mtu;
            }
        }


        /// <summary>
        /// CPU的描述
        /// </summary>
        public virtual string Descriptor
        {
            get { return this.Board.Name+"---"+this.Name; }
        }


        public BindingList<CPUChannel> Channels
        {
            get { return listChannel; }
        }
  

        public IBoard Board
        {
            get { return board; }
        }


        protected RequestPackage GetRequestPackage(int timeout)
        {
            RequestPackage package = null;
            lock (((ICollection)listRequest).SyncRoot)
            {
                if (listRequest.Count > 0)
                {
                    package = listRequest.First.Value;
                    listRequest.RemoveFirst();
                }
            }
            if (package != null || timeout == 0)
            {
                return package;
            }

            if (timeout > 0)
            {
                packageEvent.WaitOne(timeout, false);
            }
            else
            {
                packageEvent.WaitOne();
            }

            return GetRequestPackage(0);


        }





        FrameFilter filter;
        private void ProcCmd()
        {

            try
            {

                HostMachine machine = board.Machine;
                FrameManager frameManager = machine.FrameManager;


                filter = frameManager.CreateFilter();



                while (true)
                {
                    RequestPackage package = GetRequestPackage(-1);

                    if (package == null) continue;

                    filter.ClearFrame(); //清空以前的数据

                    filter.FilterDstPort = -1;
                    filter.FilterSrcPort = -1;
                    filter.FilterCmd = package.FilterCmd;
                    filter.FilterTransaction = package.FilterTransaction;



                    byte[] txData = package.TxBuffer;
                    int txLength = package.TxLength;

                    package.Reset();
                    machine.SendData(txData, txLength);
                   

                    Frame frame = filter.GetFrame(package.WaitTime);

                    package.NotifyFrame(frame);

                    if (package.CallbackHandler != null)
                    {
                        package.CallbackHandler(frame);
                    }




                }
            }
            catch (Exception)
            {

            }



        }


        public bool QueryChannelOffsetEnabled
        {
            get;
            set;
        }

        public bool QueryChannelDataEnabled
        {
            get;
            set;

        }

        /// <summary>
        /// 查询通道数据
        /// </summary>
        private void ProcQueryChannelData()
        {

            RequestPackage requestOffset = CreateRequest((byte)(QueryOffset >> 8), (byte)(QueryOffset&0xff), 1000);
            RequestPackage requestVol = CreateRequest((byte)(QueryVol >> 8), (byte)(QueryVol & 0xff), 1000);
            byte[] frameData=null;
            int dataOffset = 0;
            bool dataUpdated = false;
            while (true)
            {
                Thread.Sleep(1000);
                dataUpdated = false;
                if (QueryChannelDataEnabled)
                {
                    //查询电压
                    SendRequest(requestVol);
                    Frame frame = requestVol.WaitResponse();
                    if (frame != null)
                    {
                        dataUpdated = true;
                        frameData = frame.RawData;
                        dataOffset = frame.RealDataOffset;

                        int cnt = frame.RealDataLength / 2;
                        for (int i = 0; i < cnt; i++)
                        {
                            int volValue = frameData[dataOffset + i * 2] + (frameData[dataOffset + i * 2 + 1] << 8);
                            listChannel[i].VoltageSample = volValue.ToString();
                        }
                        if (cnt * 2 < frame.RealDataLength)
                        {
                            listChannel[cnt].VoltageSample = frameData[dataOffset + cnt * 2].ToString();
                        }



                    }
                }

                if (QueryChannelOffsetEnabled)
                {
                    //查询偏置
                    SendRequest(requestOffset);

                    Frame frame = requestOffset.WaitResponse();

                    if (frame != null)
                    {
                        dataUpdated = true;
                        frameData = frame.RawData;
                        dataOffset = frame.RealDataOffset;

                        int cnt = frame.RealDataLength / 2;
                        for (int i = 0; i < cnt; i++)
                        {
                            int volOffset = frameData[dataOffset + i * 2] + (frameData[dataOffset + i * 2 + 1] << 8);
                            listChannel[i].VoltageOffset = volOffset.ToString();
                        }
                        for (int i = cnt; i < listChannel.Count; i++)
                        {
                            listChannel[i].VoltageOffset = "---";//剩余通道
                        }

                    }
                }


               
            
                if (dataUpdated)
                {
                    if (ChannelDataUpdate != null)
                    {
                        ChannelDataUpdate(this, null);
                    }
                }
               
            }
        }



        #region ICPU 成员

        public virtual string Name
        {
            get { return "---"; }
        }

        public virtual void Start()
        {
            if (threadCmd == null || threadCmd.IsAlive == false)
            {
                threadCmd = new Thread(new ThreadStart(ProcCmd));
                threadCmd.IsBackground = true;
                threadCmd.Start();
            }
            if (QueryOffset != 0 && QueryVol != 0)
            {
                if (threadQueryChannel == null || threadQueryChannel.IsAlive == false)
                {
                    threadQueryChannel = new Thread(new ThreadStart(ProcQueryChannelData));
                    threadQueryChannel.IsBackground = true;
                    threadQueryChannel.Start();
                }
            }
          
        }

        public virtual void Stop()
        {
 
        }

        public void ClearData()
        {
            if (filter != null)
            {
                filter.ClearFrame();
            }
        }

        /// <summary>
        /// 每次发送命令
        /// </summary>
        /// <param name="package"></param>
        public void SendRequest(RequestPackage package)
        {
            this.ClearData();
            lock (((ICollection)listRequest).SyncRoot)
            {
                listRequest.AddLast(package);
                packageEvent.Set();
            }
        }

        public virtual byte DstPort
        {
            get { return 0xff; }
        }

        #endregion
    }
}
